﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Timers;
using GNF.Geo;
using System.Xml.Linq;
using GNF.GNFService.GNFClient;
using System.Windows.Threading;
using System.Threading;

namespace GNF.WPFControls
{
    /// <summary>
    /// enable loggging of the GPS Data to xml format
    /// </summary>
    public class GNFLoggerControl : AbstractGNFUserControl
    {

        #region consts

        /// <summary>
        /// the defualt time interval between logs
        /// </summary>
        private const int DefualtInterval = 100;

        #endregion

        #region private members

        private TimedOnGPSDataChangedEventHandler publishHandle;

        /// <summary>
        /// holds the timer that enable timed Logging
        /// </summary>
        private System.Timers.Timer IntervalTimer = new System.Timers.Timer(DefualtInterval);

        /// <summary>
        /// is the service running at the moment
        /// </summary>
        private bool _IsRunnging = false;

        /// <summary>
        /// contain the node of the logging service
        /// </summary>
        private XElement lognode = null;

        #endregion

        #region construction and init

        public GNFLoggerControl() : base()
        {
            Unloaded += new RoutedEventHandler(GNFLoggerControl_Unloaded);
        }

        ~GNFLoggerControl()
        {
            if (lognode != null)
            {
                lognode.Save("GPSLog.xml");
            }
        }

        #endregion

        #region public properties

        /// <summary>
        /// does the logging work at the moment
        /// </summary>
        public bool IsRunning { get { return _IsRunnging; } }

        #endregion

        #region dependency properties

        /// <summary>
        /// the file name of the saved file
        /// </summary>
        public string FileName
        {
            get { 
            //    return (string)GetValue(FileNameProperty); 
                {

                    try
                    {
                        var athis = (string)this.Dispatcher.Invoke(
                           System.Windows.Threading.DispatcherPriority.Background,
                           (DispatcherOperationCallback)delegate { return GetValue(FileNameProperty); },
                           FileNameProperty);
                        return athis;
                    }
                    catch
                    {

                        return (string)FileNameProperty.DefaultMetadata.DefaultValue;
                    }
                }
            }
            set {
                //SetValue(FileNameProperty, value);
                this.Dispatcher.BeginInvoke(DispatcherPriority.Background,
                   (SendOrPostCallback)delegate { SetValue(FileNameProperty, value); },
                   value);
            }
        }

        // Using a DependencyProperty as the backing store for FileName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FileNameProperty =
            DependencyProperty.Register("FileName", typeof(string), typeof(GNFLoggerControl), new UIPropertyMetadata("GNFLogFile"));


        /// <summary>
        /// the interval on which the data will be saved in miliseconds
        /// </summary>
        public int SaveInterval
        {
            get { return (int)GetValue(SaveIntervalProperty); }
            set { IntervalTimer.Interval= value;SetValue(SaveIntervalProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SaveInterval.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SaveIntervalProperty =
            DependencyProperty.Register("SaveInterval", typeof(int), typeof(GNFLoggerControl), new UIPropertyMetadata(DefualtInterval));


        public bool SaveOnPublish
        {
            get { return (bool)GetValue(SaveOnPublishProperty); }
            set { ChangeState(value); SetValue(SaveOnPublishProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SaveOnPublish.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SaveOnPublishProperty =
            DependencyProperty.Register("SaveOnPublish", typeof(bool), typeof(GNFLoggerControl), new UIPropertyMetadata(false));



        #endregion

        #region methods

        /// <summary>
        /// change the state of the control from logging at publish event to logging at timed intervals
        /// </summary>
        /// <param name="newstate">true for save on publish,false to save on timer</param>
        private void ChangeState(bool newstate)
        {
            if (newstate) //true for save on publish
            {
                IntervalTimer.Stop();
                _client.GPSDataChanged += publishHandle;
                
            }
            else //save on timer
            {
                _client.GPSDataChanged -= publishHandle;
                IntervalTimer.Start();
            }
        }

        

        public override void AbstractGNFUserControl_Loaded(object sender, RoutedEventArgs e)
        {
            base.AbstractGNFUserControl_Loaded(sender, e);
            publishHandle = new TimedOnGPSDataChangedEventHandler(LogOnPublish);
            //_client.Connect();
            if (SaveOnPublish)
            {
                _client.GPSDataChanged += publishHandle;
            }
            else
            {
                IntervalTimer.Elapsed += new ElapsedEventHandler(IntervalTimer_Elapsed);
                IntervalTimer.Start(); 
            }
            _IsRunnging = true;
        }

        void IntervalTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Log(_data, DateTime.Now);
        }

        /// <summary>
        /// change _data memeber to the new "data" that was received
        /// </summary>
        /// <param name="data">the new GPS Data</param>
        /// <param name="changeTime">the time of the GPS Data measurement</param>
        private void LogOnPublish(GPSData data, DateTime changeTime)
        {
            Log(data, changeTime);
          
        }

        void GNFLoggerControl_Unloaded(object sender, RoutedEventArgs e)
        {
            if (lognode != null)
            {
                lognode.Save(FileName);
            }
        }

        /// <summary>
        /// log the data into the file
        /// </summary>
        /// <param name="data">the data to log</param>
        /// <param name="time">the time the data was taken</param>
        protected virtual void Log(GPSData data, DateTime time)
        {
            try
            {
                lognode.Add(data.Save(time));
            }
            catch (Exception e)
            {
                if (lognode == null)
                {
                    if (LoadFileToLogNode())
                        Log(data, time);
                    else throw e;
                }
                else
                {
                    throw e;
                }
                
            }
        }

        private bool LoadFileToLogNode()
        {
            try
            {

                lognode = XElement.Load(FileName);
            }
            catch (Exception e)
            {
                if (lognode == null)
                {
                    lognode = new XElement("GPSLog.xml");
                }
                else
                {
                    throw e;
                }
            }
            return true;
        }

        #endregion



    }
}
